<?php


namespace app\api\controller;

use app\api\controller\send;
use app\common\controller\Api;

class Lfandcodconvert extends Api
{
    // 无需登录的接口,*表示全部
    protected $noNeedLogin = ['*'];
    // 无需鉴权的接口,*表示全部
    protected $noNeedRight = ['*'];

    // 定义mask码，用于转换
    /*
     * LF 可讀寫器可讀寫是 Page4、5 兩個信息，一般通用讀卡器會將這兩個信息顯示為 COD 10 進制數字
     * LFPage4、5码：Page 4 : FFBD FD7E  Page 5 : 3785 19EA
     * COD 10 進制數字為 3889022263
     * 轉換為 16 進制為  E7CDC537
     * 前方增加兩個 16 進制碼 77 為 廠商代碼: 77 E7CD C537
     * 最终结果：Page 4 : FFBD FD7E  Page 5 : 3785 19EA  =》 77 E7CD C537（HEX16进制数，带77廠商代碼） 3889022263（DEC10进制数）
     */

    public static $strBeginHex = 3;     // 从字符串16进制第3 个字符开始转换
    public static $strEndHex = 16;      // 到字符串16进制第16个字符结束转换，从0开始
    public static $BeginBin = 9;       // 从整个字符串2进制数的第9bit位开始，从0开始
    public static $LengthBin = 64;     // 转换2进制数的总的长度

    //    http://mg.acciot.com.tw/api/Lfpage45andcodconvert/test
    //    http://localhost:9100/api/Lfpage45andcodconvert/test
    public function test()
    {
        echo "test...." . '<BR/>';
    }

    /*
     * LFPage4、LFPage5转换为CODE码
    */
    // http://mg.acciot.com.tw/api/Lfpage45andcodconvert/LFPage45ToCOD?LFPage45=FFBDFD7E378519EA
    // http://localhost:9100/api/Lfpage45andcodconvert/LFPage45ToCOD?LFPage45=FFBDFD7E378519EA
    public function LFPage45ToCOD($LFPage45 = "")
    {
        if (strlen($LFPage45) != 16) {
            $this->error("LFpage45 length should be 16！", null, -1);
        }
        $str1 = substr($LFPage45, 0, 8);
        $str2 = substr($LFPage45, 8, 8);
        $strBin1 = base_convert($str1, 16, 2);
        $strBin2 = base_convert($str2, 16, 2);
        // 如果二进制不是4的倍数，就要在前面用0补位
        if (strlen($strBin1) / 4 != 0) {
            for ($i = 0; $i < strlen($strBin1) % 4; $i++) {
                $strBin1 = '0' . $strBin1;
            }
        }
        //echo $strBin1 . "<br>";
        // 如果二进制不是4的倍数，就要在前面用0补位
        if (strlen($strBin2) / 4 != 0) {
            for ($i = 0; $i < strlen($strBin2) % 4; $i++) {
                $strBin2 = '0' . $strBin2;
            }
        }
        //echo $strBin2 . "<br>";
        $strBin = $strBin1 . $strBin2;
        // 从二进制字符串第9位开始，循环到末尾后第6位结束
        $strLastBin = '';  // 最后合成的二进制字符串
        for ($i = self::$BeginBin; $i < self::$LengthBin - 6; $i++) {
            //echo '+++' . $strBin[$i] . "<br>";
            // 每5位是一段
            if ((($i - self::$BeginBin + 1) % 5) == 0) {
                //echo "..jump.." . "<br>";
                continue;
            }
            $strLastBin .= $strBin[$i];
            //echo "****" . $strLastBin . "<br>";
        }
        $strLastHex = strtoupper(base_convert($strLastBin, 2, 16));
        //echo "<br>" . $strLastHex;
        // 返回查询的结果
        $data = [
            'COD' => $strLastHex
        ];

        $this->success("success", $data, 0);
    }

    /*
     * COD转换为LFPage4、LFPage5码
     * 校验方法就是：
     * 1、横向：$COD每个16进制数后面要加效验码，奇数个1就是1，偶数个1就是0。
     * 2、纵向：然后所有的16进制的每个bit位，做纵向奇偶校验，包含第1个横向校验码，也做同样的效验。
     * 3、长度：19个前缀(包含77厂家代码)+40(8x5=40，即8个16进制的COD码，每个是5个bits)+5(纵向效验位 5个bits) = 64bits（16个16进制字符)
    */
    // http://mg.acciot.com.tw/api/Lfpage45andcodconvert/CODToLFPage45?COD=E7CDC537
    // http://localhost:9100/api/Lfpage45andcodconvert/CODToLFPage45?COD=E7CDC537
    public function CODToLFPage45($COD)
    {
        if (strlen($COD) != 8) {
            $this->error("COD length should be 8！", null, -2);
        }
        // 转成2进制的前缀，FFBD（hex)+111(bin)，共19个bits
        $strPreBin = '1111111110111101111';
        // $COD码要做横向和纵向奇偶效验
        $strBinOld = base_convert($COD, 16, 2);    // 共32bits
        $strBinNew = '';    // 用于保存转换后的COD码
        $odd_even_count = 0;    // 用来统计1的个数
        // 横向统计效验位
        for ($i = 0; $i <= strlen($strBinOld); $i++) {
            //先每隔4个bit，插入一个横向奇偶效验位
            if ($i != 0 and ($i % 4) == 0) {
                //echo '++++' . $strBinOld[$i] . "<br>";
                // 要判断奇偶效验位，在后面插入效验位
                if (($odd_even_count % 2) == 0) {
                    // 偶数个1，就是0
                    $strBinNew .= '0';
                } else {
                    // 奇数个1，就是1
                    $strBinNew .= '1';
                }
                // 最后一次，添加了效验位，就要结束横向效验
                if ($i == strlen($strBinOld)) {
                    break;
                }
                // $odd_even_count要重新开始计数
                $odd_even_count = 0;
            }
            if ($strBinOld[$i] == '1') {
                $odd_even_count++;
            }
            $strBinNew .= $strBinOld[$i]; // 字符数组从0开始
            //echo "-----" . $strBinNew . "<br>";
        }
        //echo "!!!!!" . $strBinNew . "<br>";
        // 纵向统计效验位
        // $strBinNew应该由原来$strBinOld的32bits，变成40bits
        $odd_even_count = 0;    // 用来统计1的个数
        // 外循环共5列
        for ($i = 0; $i < 5; $i++) {
            // 内循环共8行
            for ($j = 0; $j < 8; $j++) {
                if ($strBinNew[$i + $j * 5] == '1') {
                    $odd_even_count++;
                }
            }
            // 内循环结束就是每列已经统计完毕，要填充该列的效验位
            if (($odd_even_count % 2) == 0) {
                $strBinNew .= '0';
            } else {
                $strBinNew .= '1';
            }
            // $odd_even_count清0，重新统计下一列
            $odd_even_count = 0;
        }
        // 加上前缀就是最后的LFpage4、page5的码
        $strBinNew = $strPreBin . $strBinNew;
        //echo $strBinNew . "<br>";
        // 转换成16进制数
        $str1 = substr($strBinNew, 0, 32);
        $str2 = substr($strBinNew, 32, 32);
        $str1Hex = base_convert($str1, 2, 16);
        $str2Hex = base_convert($str2, 2, 16);
        //echo $str1Hex . "<br>";
        //echo $str2Hex . "<br>";
        $strLFpage45Hex = strtoupper($str1Hex . $str2Hex);
        //echo $strLFpage45Hex . "<br>";
        // 返回查询的结果
        $data = [
            'LFPage45' => $strLFpage45Hex
        ];

        $this->success("success", $data, 0);
    }
}